
#include "log.h"
#include "bridge.h"
#include "assert.h"

#include <stdarg.h>
#include <stdio.h>

#ifdef _MSC_VER
	#define snprintf _snprintf
#endif

void MSTP_FlushLog (BRIDGE* bridge)
{
	if (bridge->logBufferUsedSize != 0)
	{
		assert (bridge->logBufferUsedSize < bridge->logBufferSize);

		bridge->logBuffer [bridge->logBufferUsedSize] = 0;
		bridge->callbacks->debugStrOut (bridge, bridge->logCurrentPort, bridge->logCurrentTree, bridge->logBuffer);
		bridge->logBufferUsedSize = 0;
	}
}

static void WriteChar (BRIDGE* bridge, int port, int tree, char c)
{
	if ((bridge->logBufferUsedSize == bridge->logBufferSize - 1)
		|| (port != bridge->logCurrentPort) || (tree != bridge->logCurrentTree))
	{
		MSTP_FlushLog (bridge);

		bridge->logCurrentPort = port;
		bridge->logCurrentTree = tree;
	}

	bridge->logBuffer [bridge->logBufferUsedSize] = c;
	bridge->logBufferUsedSize++;
}

void MSTP_Log (BRIDGE* bridge, int port, int tree, const char* format, ...)
{
	char _buffer [10];

    va_list ap;
    va_start (ap, format);

	while (*format != 0)
	{
		if (strncmp (format, "{BID}", 5) == 0)
		{
			va_arg (ap, BRIDGE_ID*)->Dump (bridge, port, tree);
			format += 5;
		}
		else if (strncmp (format, "{BA}", 4) == 0)
		{
			va_arg (ap, BRIDGE_ADDRESS*)->Dump (bridge, port, tree);
			format += 4;
		}
		else if (strncmp (format, "{PVS}", 5) == 0)
		{
			va_arg (ap, PRIORITY_VECTOR_SHORT*)->Dump (bridge, port, tree);
			format += 5;
		}
		else if (strncmp (format, "{S}", 3) == 0)
		{
			const char* str = va_arg (ap, const char*);
			MSTP_Log (bridge, port, tree, str);
			format += 3;
		}
		else if (strncmp (format, "{T}", 3) == 0)
		{
			unsigned long v = va_arg (ap, unsigned long);
			MSTP_Log (bridge, port, tree, "{D}.{D3}", (int) (v / 1000), (int) (v % 1000));
			format += 3;
		}
		else if (strncmp (format, "{I}", 3) == 0)
		{
			int i = va_arg (ap, int);
			while (i--)
				WriteChar (bridge, port, tree, ' ');
			
			format += 3;
		}
		else if (strncmp (format, "{TN}", 4) == 0)
		{
			int i = va_arg (ap, int);
			if (i == 0)
				MSTP_Log (bridge, port, tree, "CIST");
			else
				MSTP_Log (bridge, port, tree, "MSTI_{D}", i);

			format += 4;
		}
		else if (strncmp (format, "{TMS}", 5) == 0)
		{
			const TIMES* times = va_arg (ap, TIMES*);
			MSTP_Log (bridge, port, tree, "MessageAge={D}, MaxAge={D}, HelloTime={D}, FwDelay={D}, remainingHops={D}",
					  times->MessageAge, times->MaxAge, times->HelloTime, times->ForwardDelay, times->remainingHops);
			format += 5;
		}
		else if (strncmp (format, "{D", 2) == 0)
		{
			format += 2;
			int size;
			if (*format >= '0' && *format <= '9')
			{
				size = *format - '0';
				format++;
			}
			else
				size = 0;

			assert (*format == '}');
			format++;

			int v = va_arg (ap, int);

			snprintf (_buffer, sizeof (_buffer), "%0*d", size, v);

			for (int i = 0; i < sizeof (_buffer) && _buffer [i] != 0; i++)
				WriteChar (bridge, port, tree, _buffer [i]);
		}
		else if (strncmp (format, "{X", 2) == 0)
		{
			format += 2;
			int size;
			if (*format >= '0' && *format <= '9')
			{
				size = *format - '0';
				format++;
			}
			else
				size = 0;

			assert (*format == '}');
			format++;

			int v = va_arg (ap, int);

			snprintf (_buffer, sizeof (_buffer), "%0*x", size, v);

			for (int i = 0; i < sizeof (_buffer) && _buffer [i] != 0; i++)
				WriteChar (bridge, port, tree, _buffer [i]);
		}
		else if (*format == '{')
		{
			assert (false); // not implemented
		}
		else
		{
			WriteChar (bridge, port, tree, *format);
			format++;
		}
	}

	va_end (ap);
}

